package com.ctos.oj.judge;

import cn.hutool.json.JSONUtil;
import com.ctos.oj.common.ErrorCode;
import com.ctos.oj.exception.BusinessException;
import com.ctos.oj.judge.codeSandBox.CodeSanDBoxProxy;
import com.ctos.oj.judge.codeSandBox.CodeSandBox;
import com.ctos.oj.judge.codeSandBox.CodeSandBoxFactory;
import com.ctos.oj.judge.codeSandBox.model.ExecuteCodeRequest;
import com.ctos.oj.judge.codeSandBox.model.ExecuteCodeResponse;
import com.ctos.oj.judge.startegy.JudgeContext;
import com.ctos.oj.model.dto.question.JudgeCase;
import com.ctos.oj.model.dto.questionsubmit.JudgeInfo;
import com.ctos.oj.model.entity.Question;
import com.ctos.oj.model.entity.QuestionSubmit;
import com.ctos.oj.model.enums.QuestionSubmitStatusEnum;
import com.ctos.oj.service.QuestionService;
import com.ctos.oj.service.QuestionSubmitService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class JudgeServiceImpl implements JudgeService {

    @Resource
    private QuestionSubmitService questionSubmitService;
    @Resource
    private QuestionService questionService;

    @Value("${codeSandBox.type}")
    String type;

    @Resource
    private JudgeManager judgeManager;

    @Override
    @Transactional
    public QuestionSubmit doJudge(Long questionSubmitId) {
        QuestionSubmit questionSubmit = questionSubmitService.getById(questionSubmitId);
        if (questionSubmit == null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        if (!questionSubmit.getStatus().equals((QuestionSubmitStatusEnum.WAITING).getValue())){
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目已经提交过了");
        }
        Long questionId = questionSubmit.getQuestionId();
        //根据题目id获取基本信息
        Question question = questionService.getById(questionId);
        if (question == null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        //更新判题状态
        questionSubmit.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());
        boolean updateResult = questionSubmitService.updateById(questionSubmit);
        if(!updateResult){
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目更新失败");
        }

        //调用沙箱 获取执行结果

        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();
        CodeSandBox codeSandBox = CodeSandBoxFactory.getInstance(type);
        codeSandBox = new CodeSanDBoxProxy(codeSandBox);
        ExecuteCodeRequest codeRequest = new ExecuteCodeRequest();

        String judgeCaseStr = question.getJudgeCase();
        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCaseStr, JudgeCase.class);
        List<String> QuestionInputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());

        codeRequest.setInputList(QuestionInputList);
        codeRequest.setCode(code);
        codeRequest.setLanguage(language);

        ExecuteCodeResponse executeCodeResponse = codeSandBox.executeCode(codeRequest);

        if (executeCodeResponse == null){
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "代码执行错误");
        }
        //根据结果设置题目提交表状态
        List<String> outputList = executeCodeResponse.getOutputList();
        JudgeInfo judgeInfo = executeCodeResponse.getJudgeInfo();



        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setJudgeInfo(judgeInfo);
        judgeContext.setOutputList(outputList);

        judgeContext.setQuestion(question);
        judgeContext.setQuestionSubmit(questionSubmit);
        judgeContext.setJudgeCaseList(judgeCaseList);

        JudgeResult judgeResult = judgeManager.doJudge(judgeContext);


        //修改数据库信息
        questionSubmit.setStatus(judgeResult.getStatus());
        questionSubmit.setJudgeInfo(JSONUtil.toJsonStr(judgeResult.getJudgeInfo()));
         updateResult = questionSubmitService.updateById(questionSubmit);
        if(!updateResult){
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目更新失败");
        }
        QuestionSubmit questionSubmitResult = questionSubmitService.getById(questionSubmitId);
        return questionSubmitResult;
    }
}

